package com.hfy.user.ws;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hfy.model.dto.user.OpenSessionDto;
import com.hfy.model.po.user.SessionPo;
import com.hfy.model.vo.session.SessionVo;
import com.hfy.model.ws.session.SessionOriginalMessage;
import com.hfy.user.service.SessionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.EndpointConfig;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ author 韩
 * time: 2024/11/4 11:08
 * des: 处理会话的ws操作
 */
@ServerEndpoint("/ws/session/{account}")
@Slf4j
@Component
public class WsSession {
    //声明session对象，通过该对象可以发送消息给指定的用户
    private Session session;
    // 存储session信息
    private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();


    private static ApplicationContext applicationContext;

    // 不使用静态类来存储聊天室里的用户，用redis实现
    public static void setApplicationContext(ApplicationContext applicationContext) {
        WsSession.applicationContext = applicationContext;
    }

    private static StringRedisTemplate redisTemplate;
    private static SessionService sessionService;
    private static RabbitTemplate rabbitTemplate;

    private String account;


    @OnOpen
    public void onOpen(Session session, @PathParam("account") String account, EndpointConfig config)  {
        // 配置依赖
        sessionService = applicationContext.getBean(SessionService.class);

        // 获取携带的account和roomId
        this.account = account;
        this.session = session;

        onlineUsers.put(account, session);




        log.info("OK");
    }

    @OnMessage
    public void onMessage(String message, @PathParam("account") String account) throws IOException {





        // 0. 数据准备
        // 除了data里的结构不同，外面的结构都是一样的
        SessionOriginalMessage originalMessage = JSON.parseObject(message, SessionOriginalMessage.class);
        String toAccount = originalMessage.getToAccount();
        String simpleMessage = originalMessage.getSimpleMessage();
        // 先看type 0 是清零操作
        if (originalMessage.getType().equals(0)) {
            LambdaUpdateWrapper<SessionPo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(SessionPo::getNoticeNum, 0).eq(SessionPo::getToAccount, originalMessage.getToAccount()).eq(SessionPo::getAccount, originalMessage.getAccount());
            sessionService.update(updateWrapper);
            this.session.getBasicRemote().sendText(message);
            return;
        }

        // 1. ws层面，发一条消息，解析一下，在本地发完消息，消息数要清零，simpleMessage信息不变
        // 接收客户端主要是消息数就不从数据库里拿了就直接自增就行了，一致性也不是特别大
        if (onlineUsers.get(account) != null) onlineUsers.get(account).getBasicRemote().sendText(message);

        sessionService.open(new OpenSessionDto(toAccount, account));






        // 2. 数据库层面

        // 只有数据库里有体现是不行的，还要发送websocket消息 todo

        // 更新我的会话表的信息，需要清空提示数
        LambdaUpdateWrapper<SessionPo> updateWrapper1 = new LambdaUpdateWrapper<>();
        updateWrapper1.set(SessionPo::getSimpleMessage, simpleMessage).set(SessionPo::getRecentTime, LocalDateTime.now()).set(SessionPo::getNoticeNum, 0)
                .eq(SessionPo::getAccount, account).eq(SessionPo::getToAccount, toAccount);
        sessionService.update(updateWrapper1);

        // 更新收消息人的会话表的信息，需要把它的提示数（小红点+1）
        LambdaUpdateWrapper<SessionPo> updateWrapper2 = new LambdaUpdateWrapper<>();
        updateWrapper2.set(SessionPo::getSimpleMessage, simpleMessage).set(SessionPo::getRecentTime, LocalDateTime.now()).setIncrBy(SessionPo::getNoticeNum, 1)
                .eq(SessionPo::getAccount, toAccount).eq(SessionPo::getToAccount, account);
        sessionService.update(updateWrapper2);



        SessionVo result = (SessionVo) sessionService.getSession(toAccount, account).getData();

        String resultMessage = JSON.toJSONString(result);

        if (onlineUsers.get(toAccount) != null) onlineUsers.get(toAccount).getBasicRemote().sendText(resultMessage);
    }
}
